#include "myADC.h"
#include "adc.h"
#include "math.h"

/*
 * @函数说明：ADC初始化
 * @作者：吴广金
 * @时间：2024年11月16日
 * @参数：无
 */

// ADC 和 DMA 句柄
// ADC_HandleTypeDef hadc1;
//DMA_HandleTypeDef hdma_adc1;

// DMA 传输后的数据存储数组
uint32_t adc_values[4] = {0}; // 假设有4个通道：ADC_CHANNEL_4, ADC_CHANNEL_5, ADC_CHANNEL_6, ADC_CHANNEL_7
float OUT_current = 0;  // 电流
float INT_current = 0;   // 输入电流
float solar_panel_voltage = 0; // 光伏板输入电压
float battery_voltage = 0;// 电池电压
// ADC 通道配置结构体
ADC_ChannelConfTypeDef sConfig;

// 初始化 ADC 和
void ADC_Init(void)
{
    // GPIO初始化，初始化PA4，PA5,PA6,PA7为ADC模式
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能 GPIOA 时钟
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; // 模拟输入模式
    GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // ADC 时钟使能
    __HAL_RCC_ADC1_CLK_ENABLE(); // 使能 ADC1 时钟

    // ADC1 初始化
    hadc1.Instance = ADC1;
    hadc1.Init.NbrOfDiscConversion = 0; // 不使用离散转换
    hadc1.Init.ScanConvMode = ENABLE;   // 开启扫描模式
    hadc1.Init.ContinuousConvMode = DISABLE; // 单次转换
    hadc1.Init.DiscontinuousConvMode = DISABLE; // 不使用不连续模式
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 使用软件启动
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 右对齐
    hadc1.Init.NbrOfConversion = 4; // 配置4个通道

    if (HAL_ADC_Init(&hadc1) != HAL_OK)
    {
        Error_Handler();
    }

    // 配置通道4
    sConfig.Channel = ADC_CHANNEL_4;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
        Error_Handler();
    }

    // 配置通道5
    sConfig.Channel = ADC_CHANNEL_5;
    sConfig.Rank = ADC_REGULAR_RANK_2;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
        Error_Handler();
    }

    // 配置通道6
    sConfig.Channel = ADC_CHANNEL_6;
    sConfig.Rank = ADC_REGULAR_RANK_3;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
        Error_Handler();
    }

    // 配置通道7
    sConfig.Channel = ADC_CHANNEL_7;
    sConfig.Rank = ADC_REGULAR_RANK_4;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 启动 ADC 转换（在初始化时启动一次）
    if (HAL_ADC_Start(&hadc1) != HAL_OK)
    {
        Error_Handler();
    }
}

//ch(1-6Chnnal),times(读取次数)
uint32_t ADC_Get_Average(uint8_t ch,uint8_t times)
{
	ADC_ChannelConfTypeDef sConfig;		//通道初始化
	uint32_t value_sum=0;	
	uint8_t i;
	switch(ch)							//选择ADC通道
	{
		case 1:sConfig.Channel = ADC_CHANNEL_1;break;	
		case 2:sConfig.Channel = ADC_CHANNEL_2;break;
		case 3:sConfig.Channel = ADC_CHANNEL_3;break;
		case 4:sConfig.Channel = ADC_CHANNEL_4;break;
		case 5:sConfig.Channel = ADC_CHANNEL_5;break;
		case 6:sConfig.Channel = ADC_CHANNEL_6;break;
        case 7:sConfig.Channel = ADC_CHANNEL_7;break;
	}
	sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;		//采用周期239.5周期
	sConfig.Rank = 1;
	HAL_ADC_ConfigChannel(&hadc1,&sConfig);											
	for(i=0;i<times;i++)
	{
		HAL_ADC_Start(&hadc1);								//启动转换
		HAL_ADC_PollForConversion(&hadc1,30);				//等待转化结束
		value_sum += HAL_ADC_GetValue(&hadc1);				//求和					
		HAL_ADC_Stop(&hadc1);								//停止转换
	}
	return value_sum/times;									//返回平均值
}

/*
 * @函数说明：设置ADC值
 * @作者：吴广金
 * @时间：2024年11月16日
 * @参数：无
 * @返回：无
 */
void setAadValue(void)
{
    adc_values[0] = ADC_Get_Average(4, 10);
    adc_values[1] = ADC_Get_Average(5, 10);
    adc_values[2] = ADC_Get_Average(6, 10);
    adc_values[3] = ADC_Get_Average(7, 10);
}

/* INA2401PER转换 */
float INA2401PER_getI(uint32_t adcValue)
{
    float current = (float)adcValue * 3.3 / 4095.0; // 假设 ADC 参考电压为 3.3V
    return current / 0.02;
}


/*
 * @函数说明：数据转换  
 * @作者：吴广金
 * @时间：2024年11月16日
 * @参数：无
 * @返回：无
 */
void AdcDataConversion(void)
{
    setAadValue();
    // 计算电流
    OUT_current = INA2401PER_getI(abs(adc_values[0] - 2045));
    INT_current = INA2401PER_getI(abs(adc_values[3] - 2045));
    // 计算光伏板输入电压
    solar_panel_voltage = (float)adc_values[1] * 3.3 * 11 / 4095.0 ;
    // 计算电池电压
    battery_voltage = (float)adc_values[2] * 3.3  * 11 / 4095.0;

}

void Read_ADC_Values(void)
{
    uint8_t i = 0;

    // 启动 ADC 扫描模式转换，仅一次启动
    if (HAL_ADC_Start(&hadc1) != HAL_OK)
    {
        // 启动失败处理
        Error_Handler();
    }

    // 等待所有通道的转换完成
    if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
    {
        // 读取所有通道的数据
        for (i = 0; i < 4; i++)
        {
            adc_values[i] = HAL_ADC_GetValue(&hadc1);  // 依次读取通道4、5、6、7的值
        }
    }
    else
    {
        // 转换失败处理
        Error_Handler();
    }

    // 停止 ADC 转换
    HAL_ADC_Stop(&hadc1);
}







// DMA 转换完成后的回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
//    // 此时数据已经通过 DMA 存储到 adc_values 数组
//    // 可以在这里处理 ADC 数据
//    uint32_t channel4_value = adc_values[0];    //输出检测到的ADC值 - 用来计算电流
//    uint32_t channel5_value = adc_values[1];    //光伏板输入检测到的ADC值 - 用来计算电压
//    uint32_t channel6_value = adc_values[2];    //电池电压检测到的ADC值 - 用来计算电池电压
//    uint32_t channel7_value = adc_values[3];    //电池电流检测到的ADC值 - 用来计算电池电流


    
    // 处理数据（例如打印或者其他操作）
    // printf("Channel 4: %lu, Channel 5: %lu, Channel 6: %lu, Channel 7: %lu\n", 
    //        channel4_value, channel5_value, channel6_value, channel7_value);
}
